#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "imbus_internal.h"
#include "im_slist.h"
#include "im_text.h"
#include "im_string.h"
#include "im_properties.h"

#define IM_PROP_TYPE_SHIFT          0
#define IM_PROP_CHECK_STATE_SHIFT   4
#define IM_PROP_SENSITIVE_SHIFT     6
#define IM_PROP_VISIBLE_SHIFT       7

#define IM_PROP_TYPE_MASK           0x000F
#define IM_PROP_CHECK_STATE_MASK    0x0003
#define IM_PROP_SENSITIVE_MASK      0x0001
#define IM_PROP_VISIBLE_MASK        0x0001

#define IM_PROP_HAS_KEY             0x0100
#define IM_PROP_HAS_ICON            0x0200
#define IM_PROP_HAS_LABEL           0x0400
#define IM_PROP_HAS_TIP             0x0800
#define IM_PROP_HAS_SUB_PROPS       0x1000

/************************** Declaration of internal functions ***************/
static void     __im_property_initialize        (IMPointer       prop);
static void     __im_property_finalize          (IMPointer       prop);
static void     __im_property_copy              (IMPointer       dest,
                                                 IMConstPointer  src);
static IMBool   __im_property_serialize         (IMConstPointer  obj,
                                                 IMPointer       stream);
static IMBool   __im_property_deserialize       (IMPointer       obj,
                                                 IMPointer       stream);
static void     __im_property_class_init        (IMPointer       klass);

static void     __im_prop_list_initialize       (IMPointer       prop);
static void     __im_prop_list_finalize         (IMPointer       prop);
static void     __im_prop_list_copy             (IMPointer       dest,
                                                 IMConstPointer  src);
static IMBool   __im_prop_list_serialize        (IMConstPointer  obj,
                                                 IMPointer       stream);
static IMBool   __im_prop_list_deserialize      (IMPointer       obj,
                                                 IMPointer       stream);
static void     __im_prop_list_class_init       (IMPointer       klass);

/****************** Declaration of object and class structure ************/
struct _IMProperty
{
    IMObject object;

    /* private */
    IMString    *key;
    IMString    *icon;
    IMText      *label;
    IMText      *tip;
    IMPropList  *sub_props;

    IMUInt       type : 4;
    IMUInt       check_state : 2;
    IMUInt       sensitive : 1;
    IMUInt       visible : 1;
};

struct _IMPropertyClass
{
    IMObjectClass parent_class;
};

struct _IMPropList
{
    IMObject object;

    IMSList     *props;
    IMSList     *props_tail;
};

struct _IMPropListClass
{
    IMObjectClass parent_class;
};

struct _IMPropIterator
{
    IMPropList  *list;
    IMSList     *prev;
    IMSList     *node;
};

/************************ Internal varable ************************/
static const IMObjectClass *__im_property_parent_class = 0;
static const IMObjectClass *__im_prop_list_parent_class = 0;

/************* Implementation of internal functions ***************/
/* IMProperty */
static void
__im_property_initialize (IMPointer prop)
{
    _im_assert (IM_IS_PROPERTY (prop));

    ((IMProperty*)prop)->key         = 0;
    ((IMProperty*)prop)->icon        = 0;
    ((IMProperty*)prop)->label       = 0;
    ((IMProperty*)prop)->tip         = 0;
    ((IMProperty*)prop)->sub_props   = 0;

    ((IMProperty*)prop)->type        = IM_PROPERTY_NORMAL;
    ((IMProperty*)prop)->check_state = IM_PROPERTY_UNCHECKED;
    ((IMProperty*)prop)->sensitive   = 1;
    ((IMProperty*)prop)->visible     = 1;
}

static void
__im_property_finalize (IMPointer prop)
{
    IMProperty *p = IM_PROPERTY (prop);

    _im_assert (p != 0);

    if (p->key)
        im_object_unref (p->key);
    if (p->icon)
        im_object_unref (p->icon);
    if (p->label)
        im_object_unref (p->label);
    if (p->tip)
        im_object_unref (p->tip);
    if (p->sub_props)
        im_object_unref (p->sub_props);
}

static void
__im_property_copy (IMPointer dest, IMConstPointer src)
{
    IMProperty       *dp = IM_PROPERTY (dest);
    const IMProperty *sp = IM_CONST_PROPERTY (src);

    _im_assert (dp && sp);

    __im_property_finalize (dest);

    dp->type           = sp->type;
    dp->check_state    = sp->check_state;
    dp->sensitive      = sp->sensitive;
    dp->visible        = sp->visible;

    dp->key            = (sp->key ? im_object_ref (im_object_clone (sp->key)) : 0);
    dp->icon           = (sp->icon ? im_object_ref (im_object_clone (sp->icon)) : 0);
    dp->label          = (sp->label ? im_object_ref (im_object_clone (sp->label)) : 0);
    dp->tip            = (sp->tip ? im_object_ref (im_object_clone (sp->tip)) : 0);
    dp->sub_props      = (sp->sub_props ? im_object_ref (im_object_clone (sp->sub_props)) : 0);

    /* Call copy method of parent class */
    __im_property_parent_class->copy (dest, src);
}

static IMBool
__im_property_serialize (IMConstPointer obj, IMPointer stream)
{
    const IMProperty *pp = IM_CONST_PROPERTY (obj);
    IMStream         *sp = IM_STREAM (stream);
    IMUInt16          flags;

    _im_assert (pp && sp);

    /* Call parent serialize method */
    if (!__im_property_parent_class->serialize (obj, stream))
        return FALSE;

    flags = 0;
    flags |= (pp->type << IM_PROP_TYPE_SHIFT);
    flags |= (pp->check_state << IM_PROP_CHECK_STATE_SHIFT);
    flags |= (pp->sensitive << IM_PROP_SENSITIVE_SHIFT);
    flags |= (pp->visible << IM_PROP_VISIBLE_SHIFT);

    if (pp->key && im_string_length (pp->key))
        flags |= IM_PROP_HAS_KEY;
    if (pp->icon && im_string_length (pp->icon))
        flags |= IM_PROP_HAS_ICON;
    if (pp->label && im_text_length (pp->label))
        flags |= IM_PROP_HAS_LABEL;
    if (pp->tip && im_text_length (pp->tip))
        flags |= IM_PROP_HAS_TIP;
    if (pp->sub_props && !im_prop_list_empty (pp->sub_props))
        flags |= IM_PROP_HAS_SUB_PROPS;

    if (!im_stream_put_uint16 (sp, flags))
        return FALSE;

    if (flags & IM_PROP_HAS_KEY)
        if (!im_stream_put_object (sp, pp->key)) return FALSE;
    if (flags & IM_PROP_HAS_ICON)
        if (!im_stream_put_object (sp, pp->icon)) return FALSE;
    if (flags & IM_PROP_HAS_LABEL)
        if (!im_stream_put_object (sp, pp->label)) return FALSE;
    if (flags & IM_PROP_HAS_TIP)
        if (!im_stream_put_object (sp, pp->tip)) return FALSE;
    if (flags & IM_PROP_HAS_SUB_PROPS)
        if (!im_stream_put_object (sp, pp->sub_props)) return FALSE;

    return TRUE;
}

static IMBool
__im_property_deserialize (IMPointer obj, IMPointer stream)
{
    IMProperty *pp = IM_PROPERTY (obj);
    IMStream   *sp = IM_STREAM (stream);
    IMUInt16    flags;

    _im_assert (pp && sp);

    /* Call parent deserialize method */
    if (!__im_property_parent_class->deserialize (obj, stream))
        return FALSE;

    if (im_stream_get_data_type (sp) != IM_TYPE_UINT16 || !im_stream_get_uint16 (sp, &flags))
        return FALSE;

    __im_property_finalize (obj);

    pp->type        = ((flags >> IM_PROP_TYPE_SHIFT) & IM_PROP_TYPE_MASK);
    pp->check_state = ((flags >> IM_PROP_CHECK_STATE_SHIFT) & IM_PROP_CHECK_STATE_MASK);
    pp->sensitive   = ((flags >> IM_PROP_SENSITIVE_SHIFT) & IM_PROP_SENSITIVE_MASK);
    pp->visible     = ((flags >> IM_PROP_VISIBLE_SHIFT) & IM_PROP_VISIBLE_MASK);

    pp->key         = 0;
    pp->icon        = 0;
    pp->label       = 0;
    pp->tip         = 0;
    pp->sub_props   = 0;

    if (flags & IM_PROP_HAS_KEY) {
        if (im_stream_get_data_type (sp) != IM_TYPE_STRING)
            return FALSE;

        /* Newly created IMString object should be owned by the IMProperty object.*/
        pp->key = im_object_ref (im_object_new (IM_TYPE_STRING));

        _im_assert (pp->key);

        if (!im_stream_get_object (sp, pp->key)) {
            im_object_unref (pp->key);
            pp->key = 0;
            return FALSE;
        }
    }

    if (flags & IM_PROP_HAS_ICON) {
        if (im_stream_get_data_type (sp) != IM_TYPE_STRING)
            return FALSE;

        /* Newly created IMString object should be owned by the IMProperty object.*/
        pp->icon = im_object_ref (im_object_new (IM_TYPE_STRING));

        _im_assert (pp->icon);

        if (!im_stream_get_object (sp, pp->icon)) {
            im_object_unref (pp->icon);
            pp->icon = 0;
            return FALSE;
        }
    }

    if (flags & IM_PROP_HAS_LABEL) {
        if (im_stream_get_data_type (sp) != IM_TYPE_TEXT)
            return FALSE;

        /* Newly created IMText object should be owned by the IMProperty object.*/
        pp->label = im_object_ref (im_object_new (IM_TYPE_TEXT));

        _im_assert (pp->label);

        if (!im_stream_get_object (sp, pp->label)) {
            im_object_unref (pp->label);
            pp->label = 0;
            return FALSE;
        }
    }

    if (flags & IM_PROP_HAS_TIP) {
        if (im_stream_get_data_type (sp) != IM_TYPE_TEXT)
            return FALSE;

        /* Newly created IMText object should be owned by the IMProperty object.*/
        pp->tip = im_object_ref (im_object_new (IM_TYPE_TEXT));

        _im_assert (pp->tip);

        if (!im_stream_get_object (sp, pp->tip)) {
            im_object_unref (pp->tip);
            pp->tip = 0;
            return FALSE;
        }
    }

    if (flags & IM_PROP_HAS_SUB_PROPS) {
        if (im_stream_get_data_type (sp) != IM_TYPE_PROP_LIST)
            return FALSE;

        /* Newly created IMPropList object should be owned by the IMProperty object.*/
        pp->sub_props = im_object_ref (im_object_new (IM_TYPE_PROP_LIST));

        _im_assert (pp->sub_props);

        if (!im_stream_get_object (sp, pp->sub_props)) {
            im_object_unref (pp->sub_props);
            pp->sub_props = 0;
            return FALSE;
        }
    }

    return TRUE;
}

static void
__im_property_class_init (IMPointer klass)
{
    IMObjectClass *cp = (IMObjectClass *)klass;

    cp->copy        = __im_property_copy;
    cp->serialize   = __im_property_serialize;
    cp->deserialize = __im_property_deserialize;

    __im_property_parent_class = im_object_class_get_parent (cp);
}

/* IMPropList */
static void
__im_prop_list_initialize (IMPointer proplist)
{
    ((IMPropList *) proplist)->props = 0;
    ((IMPropList *) proplist)->props_tail = 0;
}

static void
__im_prop_list_finalize (IMPointer proplist)
{
    IMPropList *p = IM_PROP_LIST (proplist);
    IMSList *iter;

    iter = p->props;
    while (iter) {
        im_object_unref (iter->data);
        iter = im_slist_next (iter);
    }

    im_slist_free (p->props);

    p->props = 0;
    p->props_tail = 0;
}

static void
__im_prop_list_copy (IMPointer dest, IMConstPointer src)
{
    IMPropList       *dp = IM_PROP_LIST (dest);
    const IMPropList *sp = IM_CONST_PROP_LIST (src);
    const IMSList *iter;
    IMSList *new_props;

    iter = sp->props;
    new_props = 0;

    while (iter) {
        new_props = im_slist_prepend (new_props, im_object_ref (im_object_clone (iter->data)));
        iter = im_slist_next (iter);
    }

    dp->props_tail = new_props;
    dp->props = im_slist_reverse (new_props);

    /* Call copy method of parent class */
    __im_prop_list_parent_class->copy (dest, src);
}

static IMBool
__im_prop_list_serialize (IMConstPointer obj, IMPointer stream)
{
    const IMPropList *lp = IM_CONST_PROP_LIST (obj);
    IMStream *sp = IM_STREAM (stream);
    IMSize size;
    const IMSList *iter;

    /* Call parent serialize method */
    if (!__im_prop_list_parent_class->serialize (obj, stream))
        return FALSE;

    size = im_slist_length (lp->props);
    if (!im_stream_put_uint32 (sp, size))
        return FALSE;

    iter = lp->props;
    while (iter) {
        if (!im_stream_put_object (sp, iter->data))
            return FALSE;
        iter = im_slist_next (iter);
    }
    return TRUE;
}

static IMBool
__im_prop_list_deserialize (IMPointer obj, IMPointer stream)
{
    IMPropList *lp = IM_PROP_LIST (obj);
    IMStream *sp = IM_STREAM (stream);
    IMSList *new_props = 0;
    IMProperty *prop;
    IMUInt32 size;
    IMType type;

    /* Call parent deserialize method */
    if (!__im_prop_list_parent_class->deserialize (obj, stream))
        return FALSE;

    if (!im_stream_get_uint32 (sp, &size))
        return FALSE;

    /* clear this property list */
    __im_prop_list_finalize (lp);

    while (size) {
        type = im_stream_get_data_type (sp);
        if (!im_type_is_a (type, IM_TYPE_PROPERTY))
            break;

        /* Newly created IMProperty object should be owned by the IMPropList object.*/
        prop = im_object_ref (im_object_new (type));

        _im_assert (prop != 0);

        if (!im_stream_get_object (sp, prop))
            break;

        new_props = im_slist_prepend (new_props, prop);

        --size;
    }

    lp->props_tail = new_props;
    lp->props = im_slist_reverse (new_props);

    return size == 0;
}

static void
__im_prop_list_class_init (IMPointer klass)
{
    IMObjectClass *cp = (IMObjectClass *) klass;

    cp->copy        = __im_prop_list_copy;
    cp->serialize   = __im_prop_list_serialize;
    cp->deserialize = __im_prop_list_deserialize;

    __im_prop_list_parent_class = im_object_class_get_parent (cp);
}

/************* Implementation of public functions ***************/
/* IMProperty */
void
__im_type_register_property ()
{
    static IMTypeInfo im_property_type_info = 
    {
        sizeof (IMPropertyClass),   /**< class_size >**/
        __im_property_class_init,   /**< class_init >**/
        0,                          /**< class_finalize >**/

        sizeof (IMProperty),        /**< instance_size >**/
        __im_property_initialize,   /**< instance_init >**/
        __im_property_finalize,     /**< instance_finalize >**/
    };

    __im_type_register_builtin_class (IM_TYPE_OBJECT,
                                      IM_TYPE_PROPERTY,
                                      "Property",
                                      &im_property_type_info,
                                      TRUE);
}

IMProperty*
im_property_new (IMString *key)
{
    return im_property_new_full (IM_PROPERTY_NORMAL, key, 0, 0, 0,
                                 TRUE, TRUE, IM_PROPERTY_UNCHECKED);
}

IMProperty*
im_property_new_full (IMPropertyType type, IMString *key, IMString *icon,
                      IMText *label, IMText *tip, IMBool sensitive,
                      IMBool visible, IMPropertyCheckState check_state)
{
    IMProperty *p;

    _im_return_val_if_fail (IM_IS_STRING (key), 0);
    _im_return_val_if_fail (!icon  || IM_IS_STRING(icon), 0);
    _im_return_val_if_fail (!label || IM_IS_TEXT(label), 0);
    _im_return_val_if_fail (!tip   || IM_IS_TEXT(tip), 0);

    p = (IMProperty *) im_object_new (IM_TYPE_PROPERTY);

    _im_assert (p != 0);

    p->type  = type;
    p->key   = key;
    p->icon  = icon;
    p->label = label;
    p->tip   = tip;
    p->sensitive = (sensitive ? 1 : 0);
    p->visible = (visible ? 1 : 0);
    p->check_state = check_state;

    if (key) im_object_ref (key);
    if (icon) im_object_ref (icon);
    if (label) im_object_ref (label);
    if (tip) im_object_ref (tip);

    return p;
}

void
im_property_set_type (IMProperty *prop, IMPropertyType type)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));

    prop->type = type;
}

IMPropertyType
im_property_get_type (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), IM_PROPERTY_NORMAL);

    return prop->type;
}

void
im_property_set_sensitive (IMProperty *prop, IMBool sensitive)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    prop->sensitive = (sensitive ? 1 : 0);
}

IMBool
im_property_is_sensitive (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), FALSE);
    return prop->sensitive != 0;
}

void
im_property_set_visible (IMProperty *prop, IMBool visible)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    prop->visible = (visible ? 1 : 0);
}

IMBool
im_property_is_visible (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), FALSE);
    return prop->visible != 0;
}

void
im_property_set_check_state (IMProperty *prop, IMPropertyCheckState state)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    prop->check_state = state;
}

IMPropertyCheckState
im_property_get_check_state (IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), IM_PROPERTY_CHECKED);
    return (IMPropertyCheckState) prop->check_state;
}

void
im_property_set_key (IMProperty *prop, IMString *key)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    _im_return_if_fail (IM_IS_STRING(key));

    if (prop->key)
        im_object_unref (prop->key);

    prop->key = key;

    if (key)
        im_object_ref (key);
}
IMString*
im_property_get_key (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), 0);
    return prop->key;
}
void
im_property_set_icon (IMProperty *prop, IMString *icon)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    _im_return_if_fail (!icon || IM_IS_STRING(icon));

    if (prop->icon)
        im_object_unref (prop->icon);

    prop->icon = icon;

    if (icon)
        im_object_ref (icon);
}
IMString*
im_property_get_icon (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), 0);
    return prop->icon;
}

void
im_property_set_label (IMProperty *prop, IMText *label)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    _im_return_if_fail (!label || IM_IS_TEXT (label));

    if (prop->label)
        im_object_unref (prop->label);

    prop->label = label;

    if (label)
        im_object_ref (label);
}
IMText*
im_property_get_label (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), 0);
    return prop->label;
}
void
im_property_set_tip (IMProperty *prop, IMText *tip)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    _im_return_if_fail (!tip || IM_IS_TEXT (tip));

    if (prop->tip)
        im_object_unref (prop->tip);

    prop->tip = tip;

    if (tip)
        im_object_ref (tip);
}
IMText*
im_property_get_tip (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), 0);
    return prop->tip;
}
void
im_property_set_sub_props (IMProperty *prop, IMPropList *subprops)
{
    _im_return_if_fail (IM_IS_PROPERTY(prop));
    _im_return_if_fail (!subprops || IM_IS_PROP_LIST(subprops));

    if (prop->sub_props)
        im_object_unref (prop->sub_props);

    prop->sub_props = subprops;

    if (subprops)
        im_object_ref (subprops);
}
IMPropList*
im_property_get_sub_props (const IMProperty *prop)
{
    _im_return_val_if_fail (IM_IS_PROPERTY(prop), 0);

    return prop->sub_props;
}

/* IMPropList */
void
__im_type_register_prop_list ()
{
    static IMTypeInfo im_prop_list_type_info = 
    {
        sizeof (IMPropListClass),   /**< class_size >**/
        __im_prop_list_class_init,  /**< class_init >**/
        0,                          /**< class_finalize >**/

        sizeof (IMPropList),        /**< instance_size >**/
        __im_prop_list_initialize,  /**< instance_init >**/
        __im_prop_list_finalize,    /**< instance_finalize >**/
    };

    __im_type_register_builtin_class (IM_TYPE_OBJECT,
                                      IM_TYPE_PROP_LIST,
                                      "PropList",
                                      &im_prop_list_type_info,
                                      TRUE);
}

IMPropList *
im_prop_list_new (void)
{
    IMPropList *proplist = (IMPropList *) im_object_new (IM_TYPE_PROP_LIST);
    _im_assert (proplist != 0);
    return proplist;
}

void
im_prop_list_clear (IMPropList *list)
{
    _im_return_if_fail (IM_IS_PROP_LIST (list));
    __im_prop_list_finalize (list);
}

IMBool
im_prop_list_empty (const IMPropList *list)
{
    _im_return_val_if_fail (IM_IS_PROP_LIST (list), TRUE);

    return list->props == 0;
}

void
im_prop_list_append (IMPropList *list, IMProperty *prop)
{
    _im_return_if_fail (IM_IS_PROP_LIST(list));
    _im_return_if_fail (IM_IS_PROPERTY(prop));

    im_object_ref (prop);

    if (!list->props) {
        list->props = im_slist_prepend (0, prop);
        list->props_tail = list->props;
    } else {
        list->props_tail = im_slist_append (list->props_tail, prop);
        list->props_tail = list->props_tail->next;
        _im_assert (list->props_tail);
    }
}

static IMSList *
__im_prop_list_find (IMPropList *list, const IMChar *key, IMSList **prev)
{
    IMSList *tmp_list;

    tmp_list = list->props;
    *prev = 0;
    while (tmp_list) {
        IMString *propkey = im_property_get_key (tmp_list->data);
        if (propkey && strcmp (im_string_c_str (propkey), key) == 0)
            return tmp_list;
        *prev = tmp_list;
        tmp_list = tmp_list->next;
    }

    return 0;
}
void
im_prop_list_remove (IMPropList *list, const IMChar *key)
{
    IMSList *tmp_list;
    IMSList *prev;

    _im_return_if_fail (IM_IS_PROP_LIST(list));
    _im_return_if_fail (key && *key);

    tmp_list = __im_prop_list_find (list, key, &prev);

    if (tmp_list) {
        im_object_unref (tmp_list->data);

        if (prev)
            prev->next = tmp_list->next;
        else
            list->props = tmp_list->next;

        im_slist_free_node (tmp_list);

        if (prev)
            tmp_list = prev->next;
        else
            tmp_list = list->props;

        if (!tmp_list)
            list->props_tail = prev;
    }
}
IMProperty*
im_prop_list_get (const IMPropList *list, const IMChar *key)
{
    IMSList *tmp_list;
    IMSList *prev;

    _im_return_val_if_fail (IM_IS_PROP_LIST(list), 0);
    _im_return_val_if_fail (key && *key, 0);

    tmp_list = __im_prop_list_find ((IMPropList *)list, key, &prev);

    if (tmp_list)
        return tmp_list->data;

    return 0;
}
void
im_prop_list_foreach (const IMPropList *list, IMFunc func, IMPointer user_data)
{
    const IMSList   *tmp_list;
 
    _im_return_if_fail (IM_IS_PROP_LIST (list));
    _im_return_if_fail (func != 0);

    tmp_list = list->props;
    while (tmp_list) {
        (*func)(tmp_list->data, user_data);
        tmp_list = im_slist_next (tmp_list);
    }
}
IMPropIterator*
im_prop_list_get_iterator (IMPropList *list)
{
    IMPropIterator *it = 0;

    _im_return_val_if_fail (IM_IS_PROP_LIST(list), 0);

    it = im_slice_new (IMPropIterator);

    _im_assert (it != 0);

    it->list = list;
    it->prev = 0;
    it->node = list->props;

    return it;
}
IMPropIterator*
im_prop_iterator_clone (const IMPropIterator *iter)
{
    IMPropIterator *new_it;

    _im_return_val_if_fail (iter != 0, 0);
    _im_return_val_if_fail (IM_IS_PROP_LIST (iter->list), 0);

    new_it = im_slice_new (IMPropIterator);
    _im_assert (new_it != 0);

    *new_it = *iter;

    return new_it;
}
void
im_prop_iterator_destroy (IMPropIterator *iter)
{
    _im_return_if_fail (iter != 0);
    im_slice_delete (IMPropIterator, iter);
}
IMBool
im_prop_iterator_next (IMPropIterator *iter)
{
    _im_return_val_if_fail (iter != 0, FALSE);
    _im_return_val_if_fail (IM_IS_PROP_LIST (iter->list), FALSE);

    if (iter->node && iter->node->next) {
        iter->prev = iter->node;
        iter->node = iter->node->next;
        return TRUE;
    }

    return FALSE;
}
IMProperty*
im_prop_iterator_get (const IMPropIterator *iter)
{
    _im_return_val_if_fail (iter != 0, 0);
    _im_return_val_if_fail (IM_IS_PROP_LIST (iter->list), 0);

    return iter->node ? iter->node->data : 0;
}
IMBool
im_prop_iterator_valid (const IMPropIterator *iter)
{
    return iter && IM_IS_PROP_LIST(iter->list) && iter->node;
}
IMBool
im_prop_iterator_equal (const IMPropIterator *iter1, const IMPropIterator *iter2)
{
    _im_return_val_if_fail (iter1 != 0, FALSE);
    _im_return_val_if_fail (iter1 != 0, FALSE);

    return iter1->list == iter2->list && iter1->node == iter2->node;
}
void
im_prop_iterator_remove (IMPropIterator *iter)
{
    IMSList *next;

    _im_return_if_fail (iter != 0);
    _im_return_if_fail (IM_IS_PROP_LIST (iter->list));

    if (!iter->node)
        return;

    next = iter->node->next;

    if (!next) iter->list->props_tail = iter->prev;

    if (!iter->prev)
        iter->list->props = next;
    else
        iter->prev->next = next;

    im_object_unref (iter->node->data);
    im_slist_free_node (iter->node);

    iter->node = next;
}

/*
vi:ts=4:nowrap:ai:expandtab
*/
